﻿//Copyright (c) 2012 Tilo Szepan, Immo Wache
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
//documentation files (the "Software"), to deal in the Software without restriction, including without limitation
//the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
//and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all copies or substantial portions 
//of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
//CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//DEALINGS IN THE SOFTWARE.


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Collections;
using System.IO;
using System.Threading;
using System.Net;
using MonoMobile.Dialogs.Remote.Discovery;

namespace DuinoClient
{
    public partial class FormMain : Form
    {
        public const string VERSION = "1.3.2";

        ListView listView;
        TreeView treeView;
        ToolStripProgressBar progress;
        ToolStripStatusLabel label;
        Button stop;
        FSReader reader;
        ComboBox pathSelect;
        TreeNode _nodeToExp;
        ListViewItem newItem;
        bool _isWaiting;
        bool _setLV;
        bool _skipReload;
        string _newName;

        public FormMain()
        {
            InitializeComponent();
            reader = new FSReader();
            reader.IsRemote = BeginWait;
            reader.Exceptions = HandleExceptions;
            reader.Result = DefaultResultHandle;
            reader.SetClipboardFileList = Clipboard.SetFileDropList;
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            SuspendLayout();
            var resources = new ComponentResourceManager(typeof(FormMain));
            var wv = createFileView(resources);
            var ai = createAddressInp(resources);
            var ts = createMainMenu();
            var sb = createStatusBar();
            ai.Dock = DockStyle.Top;
            wv.Dock = DockStyle.Fill;
            sb.Dock = DockStyle.Bottom;
            Controls.Add(wv);
            Controls.Add(ts);
            Controls.Add(ai);
            Controls.Add(sb);
            ResumeLayout(false);
            pathSelect.SelectedIndex = 1;
        }
        Control createFileView(ComponentResourceManager resources)
        {
            var sv = new SplitContainer();
            sv.BorderStyle = BorderStyle.Fixed3D;
            treeView = new TreeView();
            treeView.Dock = DockStyle.Fill;
            treeView.HideSelection = false;
            treeView.AfterSelect += new TreeViewEventHandler(treeView_AfterSelect);
            treeView.BeforeExpand += new TreeViewCancelEventHandler(treeView_BeforeExpand);
            var imgs = new ImageList();
            imgs.Images.Add((Bitmap)(resources.GetObject("dir")));
            imgs.Images.Add((Bitmap)(resources.GetObject("web")));
            treeView.ImageList = imgs;
            treeView.ImageIndex = 0;

            listView = new ListView();
            listView.Dock = DockStyle.Fill;
            listView.View = View.Details;
            listView.FullRowSelect = true;
            listView.Sorting = SortOrder.None;
            listView.Columns.Add("Name", 200, HorizontalAlignment.Left);
            listView.Columns.Add("Date", 120, HorizontalAlignment.Left);
            listView.Columns.Add("Size", 80, HorizontalAlignment.Right);
            ImageList imageListSmall = new ImageList();
            ImageList imageListLarge = new ImageList();
            var bm = ((Bitmap)(resources.GetObject("file")));
            imageListSmall.Images.Add(bm);
            imageListLarge.Images.Add(bm);
            bm = ((Bitmap)(resources.GetObject("dir")));
            imageListSmall.Images.Add(bm);
            imageListLarge.Images.Add(bm);
            imageListLarge.ImageSize = new Size(50, 50);
            listView.LargeImageList = imageListLarge;
            listView.SmallImageList = imageListSmall;
            listView.AfterLabelEdit += new LabelEditEventHandler(listView_AfterLabelEdit);
            listView.LabelEdit = true;

            listView.MouseUp += (s, e) => { if (e.Button == MouseButtons.Right) ShowContextMenu(); };
            listView.KeyDown += new KeyEventHandler(listView_KeyDown);
            listView.DoubleClick += new EventHandler(listView_DoubleClick);

            sv.Panel1.Controls.Add(treeView);
            sv.Panel2.Controls.Add(listView);
            return sv;
        }
        Control createStatusBar()
        {
            var strip = new StatusStrip();
            progress = new ToolStripProgressBar();
            progress.Alignment = ToolStripItemAlignment.Right;
            progress.Visible = false;
            progress.Step = 1;
            reader.DoStep = progress.PerformStep;
            label = new ToolStripStatusLabel();
            label.Width = 350;
            label.AutoSize = false;
            label.BorderSides = ToolStripStatusLabelBorderSides.All;
            label.BorderStyle = Border3DStyle.Sunken;
            label.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            strip.Items.Add(label);
            strip.Items.Add(progress);
            strip.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
            return strip;
        }
        Control createAddressInp(ComponentResourceManager resources)
        {
            var gb = new Control();
            var goBack = new Button();
            goBack.Image = ((Bitmap)(resources.GetObject("back")));
            goBack.AutoSize = true;
            goBack.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            goBack.Dock = DockStyle.Left;
            goBack.Click += new EventHandler(goBack_Click);

            var goUp = new Button();
            goUp.Image = ((Bitmap)(resources.GetObject("up")));
            goUp.AutoSize = true;
            goUp.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            goUp.Dock = DockStyle.Left;
            goUp.Click += new EventHandler(goUp_Click);

            pathSelect = new ComboBox();
            pathSelect.Dock = DockStyle.Fill;
            var hist = reader.ReadHistory();
            pathSelect.Items.AddRange(hist != null ? hist : FSReader.DefaultPathes);
            pathSelect.Font = new Font(pathSelect.Font.FontFamily, 12);
            pathSelect.KeyDown += new KeyEventHandler(pathSelect_KeyDown);
            pathSelect.KeyPress += new KeyPressEventHandler(pathSelect_KeyPress);
            pathSelect.Dock = DockStyle.Fill;
            pathSelect.SelectedIndexChanged += new EventHandler(pathSelect_SelectedIndexChanged);
            
            var redo = new Button();
            redo.Image = ((Bitmap)(resources.GetObject("reload")));
            redo.AutoSize = true;
            redo.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            redo.Dock = DockStyle.Right;
            redo.Click += new EventHandler(redo_Click);

            stop = new Button();
            stop.Image = ((Bitmap)(resources.GetObject("stop")));
            stop.Click += new EventHandler(stop_Click);
            stop.Enabled = false;
            stop.AutoSize = true;
            stop.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            stop.Dock = DockStyle.Right;

            var usid = new Button();
            usid.Image = ((Bitmap)(resources.GetObject("web")));
            usid.AutoSize = true;
            usid.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            usid.Dock = DockStyle.Right;
            usid.Click += delegate
            {
                var f = new ServerSelect(this);
                f.Show(this);
            };

            gb.Controls.Add(pathSelect);
            gb.Controls.Add(goUp);
            gb.Controls.Add(goBack);
            gb.Controls.Add(redo);
            gb.Controls.Add(stop);
            gb.Controls.Add(usid);
            gb.Height = 30;

            return gb;
        }

        void goUp_Click(object sender, EventArgs e)
        {
            var path = reader.GetParentDir(pathSelect.Text);
            if (path != null)
            {
                _skipReload = true;
                // if pathSelect.Items.Contains path pathSelect_SelectedIndexChanged
                // will be called, if not, not. So maybe skip, and call then
                pathSelect.Text = path;
                _skipReload = false;
                pathSelect_SelectedIndexChanged(pathSelect, null);
            }
        }

        void goBack_Click(object sender, EventArgs e)
        {
            var path = reader.LastUrl();
            if (path != null)
            {
                _skipReload = true;
                pathSelect.Text = path;
                _skipReload = false;
                pathSelect_SelectedIndexChanged(pathSelect, null);
            }
        }

        ToolStrip createMainMenu()
        {
            var menu_view = new ToolStripDropDownButton("View");
            var itms = new string[] {"Tile",
                        "LargeIcon",
                        "SmallIcon",
                        "List",
                        "Details"};
            foreach (var it in itms)
            {
                menu_view.DropDownItems.Add(it);
            }
            menu_view.DropDownItemClicked += new ToolStripItemClickedEventHandler(menu_view_ItemClicked);

            var menu_edit = new ToolStripDropDownButton("Edit");

            var cop = new ToolStripButton("Copy", null, DoCopy);
            var ins = new ToolStripButton("Paste", null, DoPaste);
            var cut = new ToolStripButton("Cut", null, DoCut);
            var del = new ToolStripButton("Delete", null, DoDelete);
            var neu = new ToolStripButton("New Folder", null, StartInsertNewFolder);
            var ren = new ToolStripButton("Rename", null, (s, e) =>
            {
                listView.SelectedItems[0].BeginEdit();
            });
            menu_edit.DropDownItems.AddRange(new ToolStripItem[]
            { cop, cut, ins, del, new ToolStripSeparator(), neu, ren });
            menu_edit.DropDownOpening += (s, e)=>
            {
                var arg = GetMenuArgs();
                cop.Enabled = arg.Copy;
                ins.Enabled = arg.FilesAvailable;
                cut.Enabled = false;
                del.Enabled = arg.Delete;
                ren.Enabled = arg.Rename;
            };

            var menu_cmd = new ToolStripDropDownButton("Commands");
            var jse = new ToolStripButton("Json Editor");
            jse.Click += delegate {
                string addr = reader.IsRemotePath(pathSelect.Text) ? pathSelect.Text : "http://";
                var f = new JSEditor(this, addr);
                f.Show(this);
            };
            menu_cmd.DropDownItems.Add(jse);
            jse.Size = new Size(70, 20);

            var menu_about = new ToolStripButton("About");
            menu_about.Click += new EventHandler(menu_about_Click);

            return new ToolStrip(menu_view, menu_edit, menu_cmd, menu_about);
        }

        void menu_about_Click(object sender, EventArgs e)
        {
            var dlg = new Form();
            var btn = new Button();
            btn.Text = "OK";
            btn.Location = new Point(180, 230);
            var lab = new Label();
            lab.Dock = DockStyle.Top;
            lab.AutoSize = true;
            lab.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            lab.Text = "\n\n\n\nDuinoExplorer\n" + VERSION + "\n\n\n         Copyright (C) 2013 by Tilo Szepan && Immo Wache\n\n\n";
            var ll = new LinkLabel();
            ll.Text = "http://duinoexplorer.codeplex.com/";
            ll.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            ll.Dock = DockStyle.Top;
            ll.LinkClicked += delegate { System.Diagnostics.Process.Start(ll.Text); };
            dlg.Controls.Add(btn);
            dlg.Controls.Add(ll);
            dlg.Controls.Add(lab);
            dlg.AcceptButton = btn;
            dlg.FormBorderStyle = FormBorderStyle.FixedDialog;
            dlg.Text = "About DuinoExplorer";
            dlg.MaximizeBox = false;
            dlg.Show();
            btn.Click += delegate { dlg.Close(); dlg.Dispose(); };
        }

        void pathSelect_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_skipReload) return;
            treeView.BeginUpdate();
            treeView.Nodes.Clear();
            string url = pathSelect.Text;
            bool isRem = reader.IsRemotePath(url);
            char stor = isRem ? '/' : '\\';
            treeView.PathSeparator = stor.ToString();
            // don't trim "C:\", then "." is interpreted by DirectoryInfo
            if (!isRem && url.Length <= 3)
            {
                if (url.Last() == ':') url = url + '\\';
            }else url = url.TrimEnd( '/' , '\\');

            _nodeToExp = treeView.Nodes.Add(url);
            if (isRem)
            {
                _nodeToExp.ImageIndex = 1;
                _nodeToExp.SelectedImageIndex = 1;
            }
            _nodeToExp.Nodes.Add("");
            treeView.EndUpdate();
            treeView.SelectedNode = _nodeToExp;
            _skipReload = true;
            treeView.SelectedNode.Expand();
            _skipReload = false;
        }
        void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            if (!_skipReload)
            {
                _nodeToExp = e.Node;
                reader.GetDirInfo(_nodeToExp.FullPath);
            }

        }
        void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            e.Node.EnsureVisible();
            listView.Items.Clear();
            _setLV = true;
            _nodeToExp = e.Node;
            _skipReload = true;
            pathSelect.Text = e.Node.FullPath;
            _skipReload = false;
            reader.GetDirInfo(pathSelect.Text);
        }
        void redo_Click(object sender, EventArgs e)
        {
            listView.Items.Clear();
            _setLV = true;
            _nodeToExp = treeView.SelectedNode;
            reader.GetDirInfo(pathSelect.Text);
        }
        void stop_Click(object sender, EventArgs e)
        {
            reader.Cancel();
            EndWait();
        }
        void pathSelect_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter && !pathSelect.DroppedDown)
            {
                SetPath(pathSelect.Text);
                e.Handled = true;
            }
        }
        void pathSelect_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete && pathSelect.DroppedDown)
            {
                pathSelect.Items.RemoveAt(pathSelect.SelectedIndex);
                e.Handled = true;
                pathSelect.DroppedDown = false;
                if (pathSelect.SelectedIndex >= pathSelect.Items.Count) pathSelect.SelectedIndex--;
                if(pathSelect.Items.Count > 0) pathSelect.DroppedDown = true;
                reader.SaveHistory(GetHistory());
            }
        }
        void menu_view_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            switch (e.ClickedItem.Text)
            {
                case "Tile": listView.View = View.Tile;
                    break;
                case "LargeIcon": listView.View = View.LargeIcon;
                    break;
                case "SmallIcon": listView.View = View.SmallIcon;
                    break;
                case "List": listView.View = View.List;
                    break;
                case "Details": listView.View = View.Details;
                    break;
            }          
        }
        void listView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control)
            {
                if (e.KeyCode == Keys.C) DoCopy(sender, null);
                if (e.KeyCode == Keys.V) DoPaste(sender, null);
                if (e.KeyCode == Keys.X) DoCut(sender, null);
            }
            if (e.KeyCode == Keys.Delete) DoDelete(sender, null);
            if (e.KeyCode == Keys.Enter) listView_DoubleClick(listView, null);
        }
        void listView_DoubleClick(object sender, EventArgs e)
        {
            var itm = listView.FocusedItem;
            if (itm != null)// && IsDir(itm))
            {
                if (IsDir(itm))
                {
                    if (!treeView.SelectedNode.IsExpanded)
                    {
                        _skipReload = true;
                        treeView.SelectedNode.Expand();
                        _skipReload = false;
                    }
                    var n = TopChildNode(treeView.SelectedNode, itm.Text);
                    if (n != null) treeView.SelectedNode = n;
                }
                else
                {
                    var path = treeView.SelectedNode.FullPath + treeView.PathSeparator + itm.Text;
                    try
                    {
                        System.Diagnostics.Process.Start(path);
                    }
                    catch (Exception exc) { }
                }
            }
        }
        void listView_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            if (newItem != null && listView.Items[e.Item] != newItem) newItem = null;

            if (newItem != null) InsertNewFolder(e);
            else
            {
                e.CancelEdit = true;
                RenameItem(e);
            }
        }
        void InsertNewFolder(LabelEditEventArgs e)
        {
            if (e.Label == "")
            {
                listView.Items.RemoveAt(e.Item);
                newItem = null;
            }
            else
            {
//                var name = e.Label ?? newItem.Text;
                _newName = e.Label ?? newItem.Text;
                string path = treeView.SelectedNode.FullPath + treeView.PathSeparator + _newName;// name;
                reader.Result = RenameResultHandle;
                reader.InsertNewFolder(path);
            }
        }
        void RenameItem(LabelEditEventArgs e)
        {
            if (!String.IsNullOrEmpty(e.Label))
            {
                var oldName = listView.Items[e.Item].Text;
                if (oldName != e.Label)
                {
                    string oldFull = treeView.SelectedNode.FullPath + treeView.PathSeparator + oldName;
                    reader.Result = RenameResultHandle;
                    _newName = e.Label;
                    reader.Rename(oldFull, e.Label);
                }
            }
        }

        void RenameResultHandle(object obj)
        {
            string name = obj as string;
            if (name == null)
            {
                if (newItem != null) listView.Items.Remove(newItem);
            }
            else
            {
                var selNode = treeView.SelectedNode;
                if (newItem != null)
                {
                    name = name.Substring(name.LastIndexOf(treeView.PathSeparator) + 1);
                    if (IsNodeLoaded(selNode))
                        selNode.Nodes.Add(name);
                    newItem = null;
                }
                else
                {
                    var itm = listView.SelectedItems[0];
                    var node = TopChildNode(selNode, itm.Text);
                    if (node != null) node.Text = name;
                    itm.Text = name;
                    _newName = null;
                }
            }
            reader.Result = DefaultResultHandle;
            EndWait();
            if (obj != null)
            {
                redo_Click(null, null);
            }
        }
        void DefaultResultHandle(object obj)
        {
            List<FileSystemItem> res = obj as List<FileSystemItem>;
            if (_nodeToExp != null)
            {
                SetTreeview(_nodeToExp, res);
                _nodeToExp = null;
            }
            if (_setLV)
            {
                SetListview(res);
                _setLV = false;
            }
            if (_isWaiting) EndWait();
        }
        void SetTreeview(TreeNode node, List<FileSystemItem> res)
        {
            treeView.BeginUpdate();
            node.Nodes.Clear();
            if (res != null)
            {
                foreach (var itm in res)
                {
                    if (itm.IsDir)
                    {
                        var nn = node.Nodes.Add(itm.Name);
                        nn.Nodes.Add("");
                    }
                }
            }
            treeView.EndUpdate();
        }
        void SetListview(List<FileSystemItem> res)
        {
            if (res != null)
            {
                listView.BeginUpdate();
                foreach (var itm in res)
                {
                    var newItm = itm.IsDir ? new ListViewItem(new[] { itm.Name, itm.Date }, 1) :
                                 new ListViewItem(new[] { itm.Name, itm.Date, itm.Size }, 0);
                    listView.Items.Add(newItm);
                }
                listView.EndUpdate();
            }
        }
        void RemoveItems(ListView.SelectedListViewItemCollection items)
        {
            listView.BeginUpdate();
            foreach (ListViewItem itm in items)
            {
                listView.Items.Remove(itm);
                if (IsDir(itm))
                {
                    TreeNode tn = TopChildNode(treeView.SelectedNode, itm.Text);
                    if (tn != null) treeView.SelectedNode.Nodes.Remove(tn);
                }
            }
            listView.EndUpdate();
        }
        TreeNode TopChildNode(TreeNode parent, string text)
        {
            foreach (TreeNode n in parent.Nodes)
            {
                if (n.Text == text)
                {
                    return n;
                }
            }
            return null;
        }
        void HandleExceptions(Exception ex)
        {
            bool done = false;
            if (ex is System.Net.WebException)
            {
                done = true;
                if ((ex as System.Net.WebException).Status == System.Net.WebExceptionStatus.RequestCanceled)
                    label.Text = "cancelled";
                else if ((ex as WebException).Response is HttpWebResponse &&
                        (int)((ex as WebException).Response as HttpWebResponse).StatusCode == 422)//.ToString().Contains("422"))
                {
                    label.Text = "bad filename";
                    if (ex.Data.Contains("Path"))
                    {
                        var path = ex.Data["Path"].ToString();
                        MessageBox.Show("A part of the path:\n" + path + "\nis invalid\nonly 8.3 names allowed", "Exception",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        redo_Click(null, null);
                    }
                    else Upload_8_3_Name();
                }
                else done = false;
            }
            if(!done)
            {
                MessageBox.Show(ex.Message + ex.StackTrace, "Exception",
                  MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
        void Upload_8_3_Name()
        {
            _newName = RenameDialog.GetGuess(this, _newName);
            if (!String.IsNullOrWhiteSpace(_newName))
            {
                if (listView.SelectedItems.Count == 1)
                {
                    string oldFull = treeView.SelectedNode.FullPath + treeView.PathSeparator + listView.SelectedItems[0].Text;
                    reader.Result = RenameResultHandle;
                    reader.Rename(oldFull, _newName);
                }
                else
                {
                    string path = treeView.SelectedNode.FullPath + treeView.PathSeparator + _newName;
                    reader.Result = RenameResultHandle;
                    reader.InsertNewFolder(path);
                }
            }
        }
        public void BeginWait(int cnt)
        {
            _isWaiting = true;
            stop.Enabled = true;
            label.Text = "loading ...";
            progress.Value = 0;// progress.Minimum;
            if (cnt > 0) progress.Maximum = cnt;
            progress.Visible = true;
            treeView.UseWaitCursor = true;
            listView.UseWaitCursor = true;
            treeView.Enabled = false;
            pathSelect.Enabled = false;
        }
        public void EndWait()
        {
            if (_isWaiting)
            {
                _isWaiting = false;
                progress.Visible = false;
                stop.Enabled = false;
                label.Text = "";
                treeView.UseWaitCursor = false;
                listView.UseWaitCursor = false;
                treeView.Enabled = true;
                pathSelect.Enabled = true;
            }
        }

        void ShowContextMenu()
        {
            var arg = GetMenuArgs();
            var cop = new ToolStripMenuItem("Copy", null, DoCopy, Keys.Control | Keys.C);
            cop.Enabled = arg.Copy;
            var ins = new ToolStripMenuItem("Paste", null, DoPaste, Keys.Control | Keys.V);
            ins.Enabled = arg.FilesAvailable;
            var cut = new ToolStripMenuItem("Cut", null, DoCut, Keys.Control | Keys.X);
            cut.Enabled = false;
            var del = new ToolStripMenuItem("Delete", null, DoDelete, Keys.Delete);
            del.Enabled = arg.Delete;
            var neu = new ToolStripMenuItem("New Folder", null, StartInsertNewFolder);
            var ren = new ToolStripMenuItem("Rename", null, (s, e) => {
                listView.SelectedItems[0].BeginEdit();
            });
            ren.Enabled = arg.Rename;
            var cm = new ContextMenuStrip();
            cm.Items.Add(cop);
            cm.Items.Add(cut);
            cm.Items.Add(ins);
            cm.Items.Add(del);
            cm.Items.Add(new ToolStripSeparator());
            cm.Items.Add(neu);
            cm.Items.Add(ren);
            cm.Show(this, PointToClient(MousePosition));
        }
        void DoCopy(object sender, EventArgs e)
        {
            var fs = SelectionToFiles();
            if(fs != null) reader.DoCopy(fs);
        }
        void DoPaste(object sender, EventArgs e)
        {
            var fs = Clipboard.GetFileDropList();
            if (fs.Count > 0)
            {
                reader.Result = (l) =>
                    {
                        reader.Result = DefaultResultHandle;
                        EndWait();
                        if (l != null)
                        {
                            redo_Click(null, null);
                        }
                    };
                reader.DoPaste(treeView.SelectedNode.FullPath + treeView.PathSeparator, fs);
            }
        }
        void DoCut(object sender, EventArgs e)
        {
            var res = MessageBox.Show(this, "Cut is not supported.\nUse Copy and Delete instead.\nDo Copy now?",
                "Cut", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            if (res == DialogResult.OK) DoCopy(sender, null);
        }
        void DoDelete(object sender, EventArgs e)
        {
            var fs = SelectionToFiles();
            if (fs != null)
            {
                var res = MessageBox.Show(this, DeleteMessage(fs),
                    "Delete", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                if (res == DialogResult.OK)
                {
                    reader.Result = (l) =>
                    {
                        if (l != null) RemoveItems(listView.SelectedItems);
                        reader.Result = DefaultResultHandle;
                        EndWait();
                    };
                    reader.DoDelete(fs);
                }
            }
        }
        string DeleteMessage(StringCollection fs)
        {
            if(fs.Count > 1)
                return "You want delete these " + fs.Count + " items?";
            bool isDir = fs[0].Last() == treeView.PathSeparator[0];// Directory.Exists(fs[0]);
            return "You want delete the " + (isDir ? "Folder:\n" : "File: \n") + fs[0] + " ?";
        }
        void StartInsertNewFolder(object sender, EventArgs e)
        {
            var it = new ListViewItem(new[] { "NewFolder", DateTime.Now.ToString() }, 1);
            newItem = listView.Items.Add(it);
            newItem.EnsureVisible();
            newItem.BeginEdit();
        }
 
        StringCollection SelectionToFiles()
        {
            var itms = listView.SelectedItems;
            if (itms.Count == 0) return null;
            string path = treeView.SelectedNode.FullPath + treeView.PathSeparator;
            var res = new StringCollection();
            foreach (ListViewItem itm in itms)
            {
                var itmpath = path + itm.Text;
                if (IsDir(itm)) itmpath += treeView.PathSeparator;
                res.Add(itmpath);
            }
            return res;
        }
        string[] GetHistory()
        {
            var res = new string[pathSelect.Items.Count];
            for (int i = 0; i < res.Length; i++)
                res[i] = pathSelect.Items[i].ToString();
            return res;
        }
        bool IsDir(ListViewItem itm)
        {
            return itm.SubItems.Count == 2;
        }
        bool IsNodeLoaded(TreeNode node)
        {
            return !(node.Nodes.Count == 1 && node.Nodes[0].Text == "");
        }

        public void SetPath(string url)
        {
            if (pathSelect.Items.Contains(url))
            {
                if (pathSelect.Text != url) pathSelect.Text = url;
                else pathSelect_SelectedIndexChanged(pathSelect, null);
            }
            else if (!String.IsNullOrEmpty(url))
            {
                pathSelect.Items.Insert(0, url);
                pathSelect.SelectedIndex = 0;
                reader.SaveHistory(GetHistory());
            }
        }
        public EditArgs GetMenuArgs()
        {
            int cnt = listView.SelectedIndices.Count;
            return new EditArgs(cnt, Clipboard.ContainsFileDropList());
        }
    }
    public class EditArgs
    {
        int cnt;
        public bool FilesAvailable { get; private set; }
        public bool Copy { get { return cnt > 0; } }
        public bool Delete { get { return cnt > 0; } }
        public bool Rename { get { return cnt == 1; } }
        public EditArgs(int selectionCnt, bool filesAvailable)
        {
            cnt = selectionCnt;
            FilesAvailable = filesAvailable;
        }
    }
}